package org.zoomdev.zoom.protobuf.modules;

import io.protostuff.ByteArrayInput;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffOutput;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.serializer.Serializer;

import java.io.IOException;
import java.lang.reflect.Type;

public final class ProtostuffArgumentSerializer implements Serializer {

    private final ISchema[] schemas;


    public ProtostuffArgumentSerializer(Type[] types) {
        this.schemas = new ISchema[types.length];
        int index = 0;
        for (Type type : types) {
            this.schemas[index++] = ISchemaFactory.create(type);
        }
    }


    @Override
    public byte[] serialize(Object data) {
        try {
            Object[] args = (Object[]) data;
            LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
            ProtostuffOutput output = new ProtostuffOutput(buffer);
            for (int i = 0, c = args.length; i < c; ++i) {
                Object value = args[i];
                if (value == null) {
                    continue;
                }
                schemas[i].write(output, i + 1, args[i], false);
            }
            return output.toByteArray();
        } catch (IOException e) {
            throw new ZoomException(e);
        }
    }

    public Object deserialize(byte[] bytes) {
        try {
            ByteArrayInput input = new ByteArrayInput(bytes, 0, bytes.length, true);
            final ISchema[] schemas = this.schemas;
            Object[] args = new Object[schemas.length];

            for (int number = input.readFieldNumber(null); number != 0; number = input.readFieldNumber(null)) {
                int i = number - 1;
                args[i] = schemas[i].mergeFrom(input);
            }
            return args;
        } catch (IOException e) {
            throw new ZoomException(e);
        }
    }

}
